/*
 * Copyright (c) 2025 CAX Conversion Project
 */
package com.comac.ins.isfd.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.encrypt.utils.EncryptUtils;
import com.comac.ins.common.excel.utils.ExcelUtil;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.enums.IsfdMetadataTableNameEnum;
import com.comac.ins.isfd.domain.IsfdCompositeMaterial;
import com.comac.ins.isfd.domain.IsfdLayupEquivalentMaterial;
import com.comac.ins.isfd.domain.IsfdLayupSkinPropertie;
import com.comac.ins.isfd.domain.IsfdOperator;
import com.comac.ins.isfd.domain.bo.IsfdLayupSkinPropertieBo;
import com.comac.ins.isfd.domain.bo.query.IsfdLayupSkinPropertieQueryBo;
import com.comac.ins.isfd.domain.vo.IsfdLayupSkinPropertieVo;
import com.comac.ins.isfd.mapper.IsfdCompositeMaterialMapper;
import com.comac.ins.isfd.mapper.IsfdLayupEquivalentMaterialMapper;
import com.comac.ins.isfd.mapper.IsfdLayupSkinPropertieMapper;
import com.comac.ins.isfd.service.IIsfdLayupSkinPropertieService;
import com.comac.ins.isfd.service.IIsfdMetadataImportService;
import com.comac.ins.isfd.util.LayupCalculateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author Lion Li
 * @date 2024-08-02
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class IsfdLayupSkinPropertieServiceImpl implements IIsfdLayupSkinPropertieService, IIsfdMetadataImportService {

    @Autowired
    private IsfdLayupSkinPropertieMapper baseMapper;
    @Autowired
    private IsfdLayupSkinPropertieMapper isfdLayupSkinPropertieMapper;
    @Autowired
    private IsfdLayupEquivalentMaterialMapper isfdLayupEquivalentMaterialMapper;
    @Autowired
    private IsfdCompositeMaterialMapper isfdCompositeMaterialMapper;

    /**
     * 查询【请填写功能名称】
     *
     * @param id 主键
     * @return 【请填写功能名称】
     */
    @Override
    public IsfdLayupSkinPropertieVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询【请填写功能名称】列表
     *
     * @param bo        查询条件
     * @return 【请填写功能名称】分页列表
     */
    @Override
    public TableDataInfo<IsfdLayupSkinPropertieVo> queryPageList(IsfdLayupSkinPropertieQueryBo bo) {
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNum(bo.getPageNum());
        pageQuery.setPageSize(bo.getPageSize());

        Wrapper<IsfdLayupSkinPropertie> wrapper = buildWrappers(bo);
        Page<IsfdLayupSkinPropertieVo> result = baseMapper.queryPageList(pageQuery.build(), wrapper);
        result.getRecords().forEach(t -> t.getIsfdLayupEquivalentMaterialVo().setPlyCode(t.getPlyCode()));
        return TableDataInfo.build(result);
    }

    protected Wrapper<IsfdLayupSkinPropertie> buildWrappers(IsfdLayupSkinPropertieQueryBo bo) {
        QueryWrapper<IsfdLayupSkinPropertie> lqw = Wrappers.query();
        lqw.eq(StringUtils.isNotBlank(bo.getPlyCode()), "lsp.ply_code", bo.getPlyCode())
            .eq(StringUtils.isNotBlank(bo.getMaterial()), "lsp.material", bo.getMaterial())
            .eq(bo.getSymmetrical() != null, "lsp.symmetrical", bo.getSymmetrical())
            .in(CollectionUtil.isNotEmpty(bo.getMetadataManagementIds()), "lsp.metadata_management_id", bo.getMetadataManagementIds())
            .orderByDesc("lsp.create_time");
        return lqw;
    }

    /**
     * 查询符合条件的【请填写功能名称】列表
     *
     * @param bo 查询条件
     * @return 【请填写功能名称】列表
     */
    @Override
    public List<IsfdLayupSkinPropertieVo> queryList(IsfdLayupSkinPropertieBo bo) {
        LambdaQueryWrapper<IsfdLayupSkinPropertie> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<IsfdLayupSkinPropertie> buildQueryWrapper(IsfdLayupSkinPropertieBo bo) {
        LambdaQueryWrapper<IsfdLayupSkinPropertie> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getPlyCode()), IsfdLayupSkinPropertie::getPlyCode, bo.getPlyCode());
        lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), IsfdLayupSkinPropertie::getMaterial, bo.getMaterial());
        lqw.eq(bo.getThickness() != null, IsfdLayupSkinPropertie::getThickness, bo.getThickness());
        lqw.eq(bo.getSymmetrical() != null, IsfdLayupSkinPropertie::getSymmetrical, bo.getSymmetrical());
        lqw.eq(StringUtils.isNotBlank(bo.getData()), IsfdLayupSkinPropertie::getData, bo.getData());
        return lqw;
    }

    /**
     * 新增【请填写功能名称】
     *
     * @param bo 【请填写功能名称】
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(IsfdLayupSkinPropertieBo bo) {
        IsfdLayupSkinPropertie add = MapstructUtils.convert(bo, IsfdLayupSkinPropertie.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改【请填写功能名称】
     *
     * @param bo 【请填写功能名称】
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(IsfdLayupSkinPropertieBo bo) {
        IsfdLayupSkinPropertie update = MapstructUtils.convert(bo, IsfdLayupSkinPropertie.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    @Transactional
    @Override
    public Boolean save(IsfdLayupSkinPropertieBo bo) {
        // 1. 参数校验
        checkParams(bo);

        // 2. 获取hash字段
        String hashUniqueKey = EncryptUtils.hashFields(bo.getPlyCode(), bo.getMaterial(), bo.getThickness(),
            bo.getSymmetrical(), bo.getData());

        // 3. 幂等校验
        Boolean isUpdate = checkUnique(bo, hashUniqueKey);

        // 4. 计算等效材料属性
        double[] equivalentMaterialProperties = this.calculate(bo);

        // 5. 落表
        IsfdLayupSkinPropertie isfdLayupSkinPropertie = MapstructUtils.convert(bo, IsfdLayupSkinPropertie.class);
        isfdLayupSkinPropertie.setHashUniqueKey(hashUniqueKey);
        // 判断是新增业务还是修改业务，处理落表的方式不同
        if (isUpdate) {
            isfdLayupSkinPropertieMapper.updateById(isfdLayupSkinPropertie);
            IsfdLayupEquivalentMaterial isfdLayupEquivalentMaterial = isfdLayupEquivalentMaterialMapper.selectById(bo.getMaterialId());
            if (isfdLayupEquivalentMaterial == null) {
                throw new BaseException("修改时，发现对应结果记录不存在，请确认后重试！");
            }

            // 校验PCOMP编号，如果重复，修改铺层编号
            String PCOMPCode = checkPCOMPCode(bo, isfdLayupEquivalentMaterial);

            isfdLayupEquivalentMaterial.setExx(equivalentMaterialProperties[0]);
            isfdLayupEquivalentMaterial.setEyy(equivalentMaterialProperties[1]);
            isfdLayupEquivalentMaterial.setGxy(equivalentMaterialProperties[2]);
            isfdLayupEquivalentMaterial.setT(equivalentMaterialProperties[3]);
            isfdLayupEquivalentMaterial.setRho(equivalentMaterialProperties[4]);
            isfdLayupEquivalentMaterial.setX(equivalentMaterialProperties[5]);
            isfdLayupEquivalentMaterial.setY(equivalentMaterialProperties[6]);
            isfdLayupEquivalentMaterial.setXy(BigDecimal.valueOf(equivalentMaterialProperties[7]));
            isfdLayupEquivalentMaterial.setPcompNumber(PCOMPCode);
            isfdLayupEquivalentMaterialMapper.updateById(isfdLayupEquivalentMaterial);
        } else {
            // 校验PCOMP编号，如果重复，修改铺层编号
            String PCOMPCode = checkPCOMPCode(bo, null);

            isfdLayupSkinPropertieMapper.insert(isfdLayupSkinPropertie);
            IsfdLayupEquivalentMaterial isfdLayupEquivalentMaterial = new IsfdLayupEquivalentMaterial();
            isfdLayupEquivalentMaterial.setPlyCode(isfdLayupSkinPropertie.getPlyCode());
            isfdLayupEquivalentMaterial.setExx(equivalentMaterialProperties[0]);
            isfdLayupEquivalentMaterial.setEyy(equivalentMaterialProperties[1]);
            isfdLayupEquivalentMaterial.setGxy(equivalentMaterialProperties[2]);
            isfdLayupEquivalentMaterial.setT(equivalentMaterialProperties[3]);
            isfdLayupEquivalentMaterial.setRho(equivalentMaterialProperties[4]);
            isfdLayupEquivalentMaterial.setX(equivalentMaterialProperties[5]);
            isfdLayupEquivalentMaterial.setY(equivalentMaterialProperties[6]);
            isfdLayupEquivalentMaterial.setXy(BigDecimal.valueOf(equivalentMaterialProperties[7]));
            isfdLayupEquivalentMaterial.setPcompNumber(PCOMPCode);
            isfdLayupEquivalentMaterialMapper.insert(isfdLayupEquivalentMaterial);
        }

        return Boolean.TRUE;
    }

    public double[] calculate(IsfdLayupSkinPropertieBo bo) {
        // 判断材料ID是否存在
        IsfdCompositeMaterial material = checkMaterialCode(bo);

        double[] compositeMaterialProperties = {material.getE1(), material.getE2(), material.getNu12(),
            material.getG12(), material.getRho(),
            material.getLongitudinalCteValue(), material.getTransverseCteValue()};
        double[] equivalentMaterialProperties = new double[8];
        LayupCalculateUtils.calculateEquivalentMaterial(bo.getPlyCode(),
            bo.getThickness(),
            bo.getSymmetrical(),
            bo.getData(),
            compositeMaterialProperties,
            equivalentMaterialProperties);

        return equivalentMaterialProperties;
    }


    private void checkParams(IsfdLayupSkinPropertieBo bo) {
        if (StringUtils.isBlank(bo.getPlyCode())) {
            throw new BaseException("铺层代码不能为空，请确认后重试！");
        }
        if (StringUtils.isBlank(bo.getMaterial())) {
            throw new BaseException("材料编号不能为空，请确认后重试！");
        }
        if (bo.getThickness() == null) {
            throw new BaseException("thickness不能为空，请确认后重试！");
        }
        if (bo.getSymmetrical() == null) {
            throw new BaseException("是否对称不能为空，请确认后重试！");
        }
        if (StringUtils.isBlank(bo.getData())) {
            throw new BaseException("铺层序列不能为空，请确认后重试！");
        }
    }

    private IsfdCompositeMaterial checkMaterialCode(IsfdLayupSkinPropertieBo bo) {
        String matCode = bo.getMaterial();
        IsfdCompositeMaterial isfdCompositeMaterial = isfdCompositeMaterialMapper.selectOne(new LambdaQueryWrapper<IsfdCompositeMaterial>()
            .eq(IsfdCompositeMaterial::getMaterialNumber, matCode));
        if (isfdCompositeMaterial == null) {
            throw new BaseException("不存在该复合材料，请修改材料编号！");
        }
        return isfdCompositeMaterial;
    }

    private String checkPCOMPCode(IsfdLayupSkinPropertieBo bo, IsfdLayupEquivalentMaterial isfdLayupEquivalentMaterial) {
        String matCode = bo.getMaterial();
        String plyCode = bo.getPlyCode();
        int matCodeInt = Integer.parseInt(matCode);
        int plyCodeInt = Integer.parseInt(plyCode);
        int PCOMPCode = (matCodeInt / 10000 * 100000) + plyCodeInt;
        IsfdLayupEquivalentMaterial oldIsfdLayupEquivalentMaterial = isfdLayupEquivalentMaterialMapper.selectOne(new LambdaQueryWrapper<IsfdLayupEquivalentMaterial>()
            .eq(IsfdLayupEquivalentMaterial::getPcompNumber, PCOMPCode));
        // isfdLayupEquivalentMaterial 为空代表新增判断
        if(isfdLayupEquivalentMaterial == null){
            if (oldIsfdLayupEquivalentMaterial != null) {
                throw new BaseException("PCOMP编号重复，请修改铺层编号！");
            }
        }else {//isfdLayupEquivalentMaterial 为空代表修改判断
            if (oldIsfdLayupEquivalentMaterial != null) {
                if (!isfdLayupEquivalentMaterial.getPcompNumber().equals(String.valueOf(PCOMPCode))){
                    throw new BaseException("PCOMP编号重复，请修改铺层编号！");
                }
            }
        }
        return String.valueOf(PCOMPCode);
    }


    @Override
    public Boolean checkUnique(IsfdLayupSkinPropertieBo bo, String hashUniqueKey) {
        Boolean isUpdate = Boolean.FALSE;
        Long id = bo.getId();
        if (id == null) {
            IsfdLayupSkinPropertie oldIsfdLayupSkinPropertie = isfdLayupSkinPropertieMapper.selectOne(new LambdaQueryWrapper<IsfdLayupSkinPropertie>()
                .eq(IsfdLayupSkinPropertie::getHashUniqueKey, hashUniqueKey));
            if (oldIsfdLayupSkinPropertie != null) {
                throw new BaseException("已经存在相同属性蒙皮，不可重复存入，请确认入参后重试！");
            }
        } else {
            IsfdLayupSkinPropertie oldIsfdLayupSkinPropertie = isfdLayupSkinPropertieMapper.selectById(id);
            if (oldIsfdLayupSkinPropertie == null) {
                throw new BaseException("修改失败，数据不存在，请确认id后重试！");
            }
            String hashUniqueKeyForDb = oldIsfdLayupSkinPropertie.getHashUniqueKey();
            if (hashUniqueKey.equals(hashUniqueKeyForDb)) {
                throw new BaseException("已经存在相同属性蒙皮，不可重复存入，请确认入参后重试！");
            }
            isUpdate = Boolean.TRUE;
        }
        return isUpdate;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(IsfdLayupSkinPropertie entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除【请填写功能名称】信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public String selectByTableName() {
        return IsfdMetadataTableNameEnum.ISFD_LAYUP_SKIN_PROPERTIE.getValue();
    }

    @Override
    public Long excelImport(File excelImportFile, String metadataManagementId) {
        long successCount = 0L;

        try (InputStream is = new FileInputStream(excelImportFile)) {
            List<IsfdLayupSkinPropertieVo> targetVo = ExcelUtil.importExcel(is, IsfdLayupSkinPropertieVo.class);
            for (IsfdLayupSkinPropertieVo vo : targetVo) {
                IsfdLayupSkinPropertieBo bo = new IsfdLayupSkinPropertieBo();
                bo.setPlyCode(vo.getPlyCode());
                bo.setMaterial(vo.getMaterial());
                bo.setThickness(vo.getThickness());
                bo.setSymmetrical(vo.getSymmetrical());
                bo.setData(vo.getData());
                try{
                    bo.setMetadataManagementId(metadataManagementId);
                    this.save(bo);
                    successCount++;
                } catch (Exception e) {
                    log.error("铺层数据导入失败", e);
                }
            }

        } catch (Exception e) {
            log.error("sheet文件转换为实体类失败", e);
            throw new BaseException("sheet文件转换为实体类失败");
        }

        return successCount;
    }



}
